package steed.listener;

import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;

import ognl.MethodAccessor;
import ognl.MethodFailedException;
import ognl.OgnlRuntime;
import steed.action.annotation.Power;
import steed.domain.GlobalParam;
import steed.util.UtilsUtil;
import steed.util.base.BaseUtil;
import steed.util.base.PathUtil;
import steed.util.base.PropertyUtil;
import steed.util.file.FileUtil;
import steed.util.system.TaskUtil;

/**
 * 启动时初始化系统
 * 
 * @author 战马
 *
 */
public class SystemInitListener implements ServletContextListener {
	@Override
	public void contextDestroyed(ServletContextEvent event) {
	}

	@Override
	public void contextInitialized(ServletContextEvent event) {
		ServletContext servletContext = event.getServletContext();
		new UtilsUtil().initUtils();
		initGlobalParam(servletContext);
		servletContext.setAttribute("path_powerMap", scanActionPowerAndDomain());
		// 启动定时任务
		new TaskUtil().init();
		fuckOGNL();
	}
	/**
	 * ognl漏洞层出不穷,日,该方法会禁止OGNL在表达式中调用Runtime,System等类
	 */
	private void fuckOGNL() {
		MethodAccessor noMethodAccessor = new MethodAccessor() {
			@Override
			public Object callStaticMethod(Map context, Class targetClass, String methodName, Object[] args)
					throws MethodFailedException {
				throw new MethodFailedException("do not run", "123");
			}

			@Override
			public Object callMethod(Map context, Object target, String methodName, Object[] args)
					throws MethodFailedException {
				throw new MethodFailedException("do not run", "123");
			}
		};
		OgnlRuntime.setMethodAccessor(Runtime.class, noMethodAccessor);
		OgnlRuntime.setMethodAccessor(System.class, noMethodAccessor);
		OgnlRuntime.setMethodAccessor(ProcessBuilder.class, noMethodAccessor);
		OgnlRuntime.setMethodAccessor(OgnlRuntime.class, noMethodAccessor);
	}

	private void initGlobalParam(ServletContext servletContext) {
		/**
		 * 获取项目路径
		 */
		GlobalParam.FOLDER.rootPath = servletContext.getRealPath("/");
		GlobalParam.FOLDER.contextPath = servletContext.getContextPath();
		GlobalParam.FOLDER.serverAddress = PropertyUtil.getConfig("site.rootURL");
		GlobalParam.FOLDER.contextUrl = GlobalParam.FOLDER.serverAddress + GlobalParam.FOLDER.contextPath;

	}

	/**
	 * 扫描action中的权限注解
	 * 
	 * @return Map<路径, 权限名>
	 */
	private Map<String, Power> scanActionPowerAndDomain() {
		String classesPath = PathUtil.getClassesPath();
		BaseUtil.getLogger().debug("classesPath--->"+classesPath);

		List<File> allFile = new FileUtil().getAllFile(classesPath, null);

		Map<String, Power> path_powerMap = new HashMap<String, Power>();
		
		String[] powerClassBlacklist = PropertyUtil.getConfig("powerClassBlacklist").split(",");
		
		for (File f : allFile) {
			String absolutePath = f.getAbsolutePath();
			if (absolutePath.endsWith("Action.class")) {
				String replaceAll = absolutePath.substring(absolutePath.indexOf("classes")+"classes.".length()).replace("\\", ".").replace("/", ".");
//				String replaceAll = absolutePath.substring(len).replace("\\", ".").replace("/", ".").replace("BOOT-INF.classes.", "");
				try {
					String className = replaceAll.substring(0, replaceAll.length() - 6);
					BaseUtil.getLogger().debug("扫描{}权限...",className);
					Class<?> actionClass = Class.forName(className);
					Power power = (Power) actionClass.getAnnotation(Power.class);
					boolean jump = false;
					for(String temp:powerClassBlacklist){
						if (jump = className.startsWith(temp)) {
							//TODO 把对应数据库权限status=1（停用），
							//steed.ext.domain.user.Power power = new steed.ext.domain.user.Power(name);
							break;
						}
					}
					if(jump){
						continue;
					}
					Namespace nameSpace = (Namespace) actionClass.getAnnotation(Namespace.class);
					if (nameSpace == null) {
						continue;
					}
					String nameSpacePath = nameSpace.value() + "/";
					if (power != null) {
						path_powerMap.put(nameSpacePath, power);
					}
					for (Method m : actionClass.getMethods()) {
						Power methodPower = m.getAnnotation(Power.class);
						if (methodPower != null) {
							String path;
							Action action = m.getAnnotation(Action.class);
							if (action != null) {
								path = action.value();
							} else {
								path = m.getName();
							}
							path_powerMap.put(String.format("%s%s%s", nameSpacePath, path, ".act"),
									methodPower);
						}
					}
				} catch (ClassNotFoundException e) {
					BaseUtil.getLogger().error("扫描权限出错!!",e);
				}
			}
		}

		return path_powerMap;
	}

}
